package cloud.xlh.my_system.flow;

import cloud.xlh.domin.DO.UserDO;
import cloud.xlh.domin.dto.UserDTO;
import cloud.xlh.domin.po.UserPO;
import cloud.xlh.infrastructure.utils.CommonUtil;
import cloud.xlh.infrastructure.utils.FileUtil;
import cloud.xlh.my_system.service.UserService;
import cloud.xlh.my_system.tradeflow.EcnyTradeContext;
import cloud.xlh.my_system.tradeflow.EcnyTradeFlowBuilder;
import cloud.xlh.my_system.tradeflow.TradeContext;
import cloud.xlh.my_system.tradeflow.TradeFlow;
import cloud.xlh.my_system.utils.RsaUtil;
import cloud.xlh.utils.StackTraceUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCrypt;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 *
 * @ project name : xlh_osms
 * @ Author: XuLeHuang
 * @ Date: 2023/1/9 18:26
 * @ Description:
 */
@Configuration
@Slf4j
public class UserRegisterFlow {
    public static final String TRADE_FLOW = "UserRegisterFlow";
    private static final String USER_DO_KEY = "userDO";

    @Value("${keyPropertiesLocation}")
    private String keyPropertiesLocation;

    @Resource
    private UserService userService;

    /**
     * 用户注册
     *
     * @return
     */
    @Bean(name = TRADE_FLOW)
    public TradeFlow UserRegisterFlow() {
        return EcnyTradeFlowBuilder.get()
                .process(this::init)
                .process(this::check)
                .process(this::response)
                .errHandler(this::tradeErrHandler)
                .build();
    }

    private void init(TradeContext<?, ?> tradeContext) {
        log.info("pushed init method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        //DTO->DO
        UserDTO reqMsg = EcnyTradeContext.getReqMsg(tradeContext);
        UserDO userDO = new UserDO();
        CommonUtil.copyPropertiesIgnoreCase(reqMsg , userDO);
        tradeContext.getTempCtx().put(USER_DO_KEY , userDO);
        log.info("ready pop init method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
    }

    private void check(TradeContext<?, ?> tradeContext) {
        log.info("pushed check method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        UserDO userDO = (UserDO) tradeContext.getTempCtx().get(USER_DO_KEY);

        //参数校验
        if (userDO == null)
            throw new RuntimeException("");
        //当前用户是否存在


        registerUser(userDO);
        log.info("ready pop check method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
    }

    private boolean registerUser(UserDO userDO) {
        log.info("pushed registerUser method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        String encryptedPassword = userDO.getPassword();
        String decryptedPassword = parsePassword(encryptedPassword);
        //构建PO
        UserPO userPO = new UserPO();
        CommonUtil.copyPropertiesIgnoreCase(userDO , userPO);
        String encryptedPasswordWithBCrypt = encryptPasswordWithBCrypt(decryptedPassword);
        userPO.setPassword(encryptedPasswordWithBCrypt);
        userPO.setId(UUID.randomUUID().toString().substring(0 , 16));
        Date date = new Date();
        userPO.setCreateTime(date);
        userPO.setUpdateTime(date);
        userPO.setStatus("00");
        doRegisterUser(userPO);
        log.info("ready pop registerUser method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        return true;
    }

    private String encryptPasswordWithBCrypt(String decryptedPassword) {
        log.info("pushed encryptPasswordWithBCrypt method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        log.info("加密前密码->{}" , decryptedPassword);
        //盐值
        String salt = BCrypt.gensalt();
        //加密后的前29位是盐
        String encryptedPasswordWithBCrypt = BCrypt.hashpw(decryptedPassword, salt);
        log.info("BCrypt加密后密码->{}" , encryptedPasswordWithBCrypt);
        log.info("BCrypt密码验证结果->{}" ,BCrypt.checkpw(decryptedPassword , encryptedPasswordWithBCrypt));
        log.info("ready pop encryptPasswordWithBCrypt method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        return encryptedPasswordWithBCrypt;
    }

    private boolean doRegisterUser(UserPO userPO) {
        log.info("pushed doRegisterUser method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        //todo 入库
        int rows = userService.register(userPO);
        userPO.setId(UUID.randomUUID().toString());
        log.info("ready pop doRegisterUser method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        return false;
    }

    private String parsePassword(String encryptedPassword) {
        log.info("pushed parsePassword method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        //base64解码加密字符串
        String encryptedPasswordDecodeWithBase64 = null;
        try {
            encryptedPasswordDecodeWithBase64 = new String(Base64.decodeBase64(encryptedPassword), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //rsa私钥解密加密字符串
        String decryptedPassword = "";
        try {
             String rsaPrivateKey = getRsaPrivateKey();
             decryptedPassword = RsaUtil.decrypt(encryptedPasswordDecodeWithBase64, rsaPrivateKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int length = decryptedPassword.length();
        String reallyPassword = decryptedPassword.substring(0 , length - 3);
        log.info("ready push parsePassword method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        return reallyPassword;
    }

    private String getRsaPrivateKey() {
        Properties properties = FileUtil.readKeyPropertiesFile(FileUtil.PathTypeCode.ABSOLUTE_PATH.getCode(), keyPropertiesLocation , false);
        String rsaPrivateKey = properties.getProperty("rsaPrivateKey");
        return rsaPrivateKey;
    }

    private void response(TradeContext<?, ?> tradeContext) {
        log.info("pushed response method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
        UserDTO reqMsg = (UserDTO) EcnyTradeContext.getReqMsg(tradeContext);
        log.info("DTO数据->{}" , reqMsg);
        UserDTO userDTO = new UserDTO();
        EcnyTradeContext.setRspMsg(tradeContext , userDTO);
        log.info("ready pop response method，log print location is -> {}" , StackTraceUtil.getCurrentLocation(Thread.currentThread()));
    }

    private void tradeErrHandler(TradeContext<?,?> tradeContext, Throwable throwable) {
    }
}
